#!/usr/bin/perl

package get_features_overlapping_region;

use strict;
use warnings;

use lib 'lib';
use base 'SADI::Simple::AsyncService';

#-----------------------------------------------------------------
# SERVICE CONFIGURATION PART
#-----------------------------------------------------------------

use SADI::GMOD::Config qw(
    get_base_url
    get_gmod_name
);

my %config = (

    ServiceName => sprintf('get_features_overlapping_region%s', get_gmod_name() ? sprintf(' (%s)', get_gmod_name()) : ''),
    Description => 'get sequence features overlapping a specified region of a sequence feature',
    InputClass => 'http://sadiframework.org/ontologies/GMOD/BiopolymerRegion.owl#BiopolymerRegion',
    OutputClass => 'http://sadiframework.org/ontologies/GMOD/service/get_features_overlapping_region.owl#OutputClass',   
    Authority => 'sadiframework.org', 
    Provider => 'ben.vvalk@gmail.com',
    URL => get_base_url . 'get_features_overlapping_region', # only required for asynchronous services

);

#-----------------------------------------------------------------
# CGI HANDLER PART
#-----------------------------------------------------------------

use Log::Log4perl;

Log::Log4perl->init('log4perl.properties');

my $service = get_features_overlapping_region->new;
$service->handle_cgi_request;

#-----------------------------------------------------------------
# SERVICE IMPLEMENTATION PART
#-----------------------------------------------------------------

use SADI::GMOD::Config qw(
    get_db_args
    get_gff_id_to_dbxref_mapping
);
use RDF::Trine::Node::Resource;
use RDF::Trine::Node::Literal;
use RDF::Trine::Statement;
use RDF::Trine::Parser;
use Bio::DB::SeqFeature::Store::Extended;
use Utils::Dbxref qw(
    id_type_to_dbxref
    get_feature_by_primary_dbxref
);
use Utils::BiopolymerRegion qw(parse_biopolymer_region);
use Utils::Trine qw(is_uri_resource);
use Vocab::SIO qw(SIO_ONTOLOGY_PREFIX);

=head2 new 

 Function: create a new instance of the service
 
=cut

sub new {
    my $class = shift;
    my $self = $class->SUPER::new(%config);
    bless($self, $class);
    return $self;
}

=head2 process_it

 Function: implements the business logic of a SADI service
 Args    : $inputs - ref to an array of RDF::Trine::Node::Resource
           $input_model - an RDF::Trine::Model containing the input RDF data
           $output_model - an RDF::Trine::Model containing the output RDF data
 Returns : nothing (service output is stored in $output_model)

=cut

sub process_it {

    my ($self, $inputs, $input_model, $output_model) = @_;

    my $log = Log::Log4perl->get_logger('get_feature_info');
    my $db = Bio::DB::SeqFeature::Store::Extended->new(get_db_args, -gff_id_to_dbxref => get_gff_id_to_dbxref_mapping);
    my $parser = RDF::Trine::Parser->new('turtle');
    my $templater = Template->new;
    my $overlaps = RDF::Trine::Node::Resource->new(SIO_ONTOLOGY_PREFIX . 'SIO_000325');
    my %visited_features = ();

    foreach my $input (@$inputs) {

        next unless is_uri_resource($input);
        
        $log->info(sprintf('processing input %s', $input->uri));

        #------------------------------------------------------------
        # parse the input graph (BiopolymerRegion)
        #------------------------------------------------------------

        my ($feature, $start_pos, $end_pos, $strand) = parse_biopolymer_region($input_model, $input->uri, $db);
        next unless $feature;

        #------------------------------------------------------------
        # get the sequence string
        #------------------------------------------------------------

        my @segments = $db->segment($feature->display_name, $start_pos, $end_pos);

        if(!@segments) {
            $log->logdie(sprintf(
                    "could not build segment object for feature \'%s\', range (%d .. %d)", 
                    $feature->display_name,
                    $start_pos,
                    $end_pos
                ));
        }

        if (@segments > 1) {
            $log->warn(sprintf('multiple matches for feature name \'%s\', using only the first match', $feature->display_name));
        }

        my $segment = $segments[0];
        my $it = $segment->features(-range_type => 'overlaps', -iterator => 1);

        #------------------------------------------------------------
        # encode the output RDF
        #------------------------------------------------------------

        while (my $feature = $it->next_seq) {

            $feature = Bio::SeqFeature::Extended->new($feature, $db);
            
            next unless $feature->uri;
            
            my $feature_node = RDF::Trine::Node::Resource->new($feature->uri);
            my $statement = RDF::Trine::Statement->new($input, $overlaps, $feature_node);
            $output_model->add_statement($statement);

            if (!$visited_features{$feature->uri}) {
                $parser->parse_into_model(undef, $feature->ttl, $output_model);
                $visited_features{$feature->uri} = 1;
            }

            my $ref_feature = $feature->ref_feature;

            if (!$visited_features{$ref_feature->uri}) {
                $parser->parse_into_model(undef, $ref_feature->ttl, $output_model);
                $visited_features{$ref_feature->uri} = 1;
            }

        }

    }
}

1;

__END__
